
/*
名称 : 阿里云断点续传组件
作者 : 唐成
日期 : 2019-05-05
版本 : 1.0
描述 : 此组件用来做附件上传用,同时支持断点续传功能
使用 : 请参见文件底部:调用格式说明
*/

var zcAliFile = {
  KeyConfig: "ZcSoft_Vue_KeTi_Web_OssConfig",
  OssCfg: {},
  setConfig() {
    let me = this;
    let ossConfig = {};
    ossConfig.AppId = "LTAItVNI8d5WCDZB";
    ossConfig.Secret = "GcARvstYiqWQyCAbXcQbKrv7qwomUT";
    ossConfig.Bucket = "zcsoft-education";
    ossConfig.Region = "oss-cn-qingdao";
    ossConfig.DirName = "tzc2";
    let valConfig = JSON.stringify(ossConfig);
    localStorage.setItem(me.KeyConfig, valConfig);
  },
  initConfig() {
    let me = this;
    me.setConfig();
    let valConfig = localStorage.getItem(me.KeyConfig);
    if (valConfig) {
      me.OssCfg = JSON.parse(valConfig);
    }
  },
  doInit(options) {
    let me = this;
    me.initConfig();
    if (!options.AliOss) {
      window.alert('请配置AliOss参数!');
      return;
    }
    if (!options.Scope.$ZcPublic.Server) {
      window.alert('请配置Server参数!');
      return;
    }
    if (!me.OssCfg) {
      window.alert('请配置OssCfg参数!');
      return;
    }
    if (!options.FileCfg) {
      window.alert('请配置FileCfg参数!');
      return;
    }
    if (!options.UserData || me.isEmptyObject(options.UserData)) {
      window.alert('请配置UserData参数!');
      return;
    }
    if (!options.UserData.Uploader || me.isEmptyObject(options.UserData.Uploader)) {
      window.alert('请配置UserData中的Uploader参数!');
      return;
    }
    if (!options.fnUpingProgress) {
      window.alert('请配置fnUpingProgress参数!');
      return;
    }
    if (!options.fnUpingSuccess) {
      window.alert('请配置fnUpingSuccess参数!');
      return;
    }
    if (!options.fnUpingError) {
      window.alert('请配置fnUpingError参数!');
      return;
    }
    options.ServerPara = {};
    if (options.FileCfg.ButtonId) {
      let inputId = this.getSysGuid() + '-inputfile-' + me.getUserGuid();
      let input = document.createElement('input');
      options.UserData.Uploader.InputId = inputId;
      input.id = inputId;
      input.type = 'file';
      input.accept = options.FileCfg.Accept;
      input.style.display = 'none';
      input.onchange = function(e) {
        let file = e.target.files[0];
        if (file) {
          let extName = me.getExtName(file.name);
          let maxSize = me.getBytes(options.FileCfg.MaxSize);
          if (maxSize < 0) {
            if(options.fnUpingError) {
              options.fnUpingError({
                name: "限制文件大小",
                msg: "参数FileCfg中的MaxSize配置不正确!",
                errCode: "errSizeCfg"
              }, options);
            }
            return;
          }
          if (options.FileCfg.ExtName.indexOf(extName) < 0) {
            if(options.fnUpingError) {
              options.fnUpingError({
                name: "限制文件类型",
                msg: "对不起,不支持此文件类型!",
                errCode: "errFileType"
              }, options);
            }
            return;
          }
          else if (file.size > maxSize) {
            window.alert();
            if(options.fnUpingError) {
              options.fnUpingError({
                name: "限制文件大小",
                msg: "对不起,文件大小不能超过" + options.FileCfg.MaxSize + "!",
                errCode: "errFileSize"
              }, options);
            }
            return;
          }
          else {
            me.doAliFile(options, file);
          }
        }
      }
      document.getElementById("divUpFileList").appendChild(input);
      document.getElementById(options.FileCfg.ButtonId).setAttribute('data-fileid', inputId);
      document.getElementById(options.FileCfg.ButtonId).addEventListener('click', function (e) {
        if (e.preventDefault) {
          e.preventDefault();
        }
        let fileId = e.target.dataset.fileid;
        document.getElementById(fileId).click();
      }, false);
    }
  },
  doNormRestore (options) {
    let me = this;
    if (!options.ServerPara)
      options.ServerPara = {};

    let keyCheckPoint = options.UserData.Uploader.KeyCheckPoint;
    let valCheckPoint = localStorage.getItem(keyCheckPoint);
    if (valCheckPoint) {
      let tempCheckPoint = JSON.parse(valCheckPoint);
      if (tempCheckPoint) {
        options.ServerPara.GB_OrganSN="237CA873-8BB2-453E-900A-87BF324D5F75";
        options.ServerPara.PersonSN = "FromVue";
        options.ServerPara.FileName = options.UserData.Uploader.File.name;
        options.ServerPara.ObjName = tempCheckPoint.name;
        options.ServerPara.FileSize = me.getSize(options.UserData.Uploader.File.size);
        options.ServerPara.ExtName = me.getExtName(options.UserData.Uploader.File.name);

        tempCheckPoint.file = options.UserData.Uploader.File;
        let client = options.UserData.Uploader.Client;
        async function resumeUpload() {
          try {
            let result = await client.multipartUpload(tempCheckPoint.name, tempCheckPoint.file, {
              progress: async function (fPercent, checkpoint) {
                var percent = parseInt(fPercent * 100);
                if (options.fnUpingProgress) {
                  if (percent === 100) {
                    window.setTimeout(function() {
                      options.fnUpingProgress(percent, {
                        UserData:options.UserData
                      });
                      options.Scope.$ZcPublic.Server.PostOss({
                        IsNeedLogin: "false",
                        Paras: options.ServerPara,
                        Callback: options.fnUpingSuccess,
                        Source: options
                      });
                      me.clearCheckPoint(options.UserData.Uploader.KeyCheckPoint);
                      me.doClearInput(options);
                    }, 2000);

                  }
                  else {
                    options.fnUpingProgress(percent, {
                      UserData:options.UserData
                    });
                    me.setCheckPoint(options.UserData.Uploader.KeyCheckPoint, checkpoint);
                  }
                }
              },
              checkpoint: tempCheckPoint
            })
          }
          catch (e) {
            console.log(e);
          }
        }
        resumeUpload();
      }
    }
  },
  doInitRestore(options, tempCheckPoint) {
    let me = this;
    if (options.fnFileAdded) {
      options.fnFileAdded({
        UserData: options.UserData
      });
    }
    let client = options.UserData.Uploader.Client;
    async function resumeUpload() {
      try {
        let result = await client.multipartUpload(tempCheckPoint.name, tempCheckPoint.file, {
          progress: async function (fPercent, checkpoint) {
            var percent = parseInt(fPercent * 100);
            if (options.fnUpingProgress) {
              if (percent === 100){
                window.setTimeout(function() {
                  options.fnUpingProgress(percent, {
                    UserData:options.UserData
                  });
                  options.Scope.$ZcPublic.Server.PostOss({
                    IsNeedLogin: "false",
                    Paras: options.ServerPara,
                    Callback: options.fnUpingSuccess,
                    Source: options
                  });
                  me.clearCheckPoint(options.UserData.Uploader.KeyCheckPoint);
                  me.doClearInput(options);
                }, 2000);
              }
              else{
                options.fnUpingProgress(percent, {
                  UserData:options.UserData
                });
                me.setCheckPoint(options.UserData.Uploader.KeyCheckPoint, checkpoint);
              }
            }
          },
          checkpoint: tempCheckPoint
          //meta: { year: 2017, people: 'test' },
          //mime: 'image/jpeg'
        })
      }
      catch (e) {
        console.log(e);
      }
    }
    resumeUpload();
  },
  getFileKey(file) {
    let key = "";
    if (file) {
      key = file.lastModified + file.name + file.size + file.type;
    }
    return key;
  },
  setCheckPoint(keyCheckPoint, tempCheckPoint) {
    let locCheckPoint = {};
    locCheckPoint.doneParts = tempCheckPoint.doneParts;
    locCheckPoint.file = {};
    locCheckPoint.fileSize = tempCheckPoint.fileSize;
    locCheckPoint.name = tempCheckPoint.name;
    locCheckPoint.partSize = tempCheckPoint.partSize;
    locCheckPoint.uploadId = tempCheckPoint.uploadId;

    let valCheckPoint = JSON.stringify(locCheckPoint);
    localStorage.setItem(keyCheckPoint, valCheckPoint);
  },
  clearCheckPoint(keyCheckPoint) {
    localStorage.removeItem(keyCheckPoint);
  },
  doAliFile(options, file) {
    let me = this;
    if (options.AliOss && me.OssCfg) {
      //读取参数
      let dirName = me.getDirName(me.OssCfg.DirName);
      let keyName = me.getSysGuid() + '-FromVue-' + me.getUserGuid();
      let extName = me.getExtName(file.name);
      let objName = dirName + keyName + extName;
      let fileSize = me.getSize(file.size);

      //上传成功后,访问Web服务器所需的参数
      options.ServerPara.GB_OrganSN ='237CA873-8BB2-453E-900A-87BF324D5F75';
      options.ServerPara.PersonSN= 'FromVue';
      options.ServerPara.FileName = file.name;
      options.ServerPara.ObjName = objName;
      options.ServerPara.FileSize = fileSize;
      options.ServerPara.ExtName = extName;

      //初始化客户端
      let client = new options.AliOss({
        accessKeyId: me.OssCfg.AppId,
        accessKeySecret: me.OssCfg.Secret,
        bucket: me.OssCfg.Bucket,
        region: me.OssCfg.Region
      });

      let keyCheckPoint = me.getFileKey(file);
      options.UserData.Uploader.KeyCheckPoint = keyCheckPoint;
      options.UserData.Uploader.Client = client;
      options.UserData.Uploader.File = file;

      let valCheckPoint = localStorage.getItem(keyCheckPoint);
      let isPointUpload = false;
      if (valCheckPoint) {
        //说明此文件上次未上传完成,因此需要断点续传
        let tempCheckPoint = JSON.parse(valCheckPoint);
        if (tempCheckPoint) {
          tempCheckPoint.file = file;
          options.ServerPara.ObjName = tempCheckPoint.name;
          isPointUpload = true;
          me.doInitRestore(options, tempCheckPoint);
        }
      }
      if (isPointUpload === false) {
        if (options.fnFileAdded) {
          options.fnFileAdded({
            UserData:options.UserData
          });
        }
        async function multiPartUpload() {
          try {
            let result = await client.multipartUpload(objName, file, {
              progress: async function (fPercent, checkpoint) {
                var percent = parseInt(fPercent * 100);
                if(options.fnUpingProgress) {
                  if(percent === 100) {
                    window.setTimeout(function() {
                      options.fnUpingProgress(percent, {
                        UserData:options.UserData
                      });
                      options.Scope.$ZcPublic.Server.PostOss({
                        IsNeedLogin: "false",
                        Paras: options.ServerPara,
                        Callback: options.fnUpingSuccess,
                        Source: options
                      });
                      me.clearCheckPoint(options.UserData.Uploader.KeyCheckPoint);
                      me.doClearInput(options);
                    }, 2000);
                  }
                  else {
                    options.fnUpingProgress(percent, {
                      UserData:options.UserData
                    });
                    me.setCheckPoint(options.UserData.Uploader.KeyCheckPoint, checkpoint);
                  }
                }
              }
            });
          }
          catch(e) {
            if (typeof (e) === "object"){
              if (e.name === "cancel" && e.status === 0) {
                // 上传暂停
                e.errCode = "errUpPause";
                e.msg = "上传暂停!"
              }
            }
            else{
              let errMsg = e;
              e = {
                name: "未知",
                msg: errMsg,
                errCode: "errUnKnow"
              }
            }
            if(options.fnUpingError) {
              options.fnUpingError(e, options);
            }
          }
        }
        multiPartUpload();
      }
    }
  },
  doClearInput(options){
    let me = this;
    try{
      if (options.UserData.Uploader.InputId) {
        let curInputFile = document.getElementById(options.UserData.Uploader.InputId);
        curInputFile.value = "";
      }
    }
    catch (e) {
      console.log('doClearInput-Err:',e.message);
    }
  },
  getSysGuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
      return v.toString(16);
    });
  },
  getUserGuid() {
    let sec_1_8 = this.getRandom(8);
    let sec_2_4 = this.getRandom(4);
    let sec_3_4 = this.getRandom(4);
    let sec_4_4 = this.getRandom(4);
    let sec_5_12 = this.getRandom(12);
    return sec_1_8 + '-' + sec_2_4 + '-' + sec_3_4 + '-' + sec_4_4 + '-' + sec_5_12;
  },
  getRandom(len) {
    len = len || 32;
    let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let maxPos = chars.length;
    let pwd = '';
    for (let i = 0; i < len; i++) {
      pwd += chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
  },
  getSize(bytes) {
    if (bytes === 0) return '0B';
    let unit = 1024;
    let Word = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    let idxWord = Math.floor(Math.log(bytes) / Math.log(unit));
    let resSize = (bytes / Math.pow(unit, idxWord)).toPrecision(3) + ' ' + Word[idxWord];
    return resSize;
  },
  getBytes(limitSize) {
    let resSize = 0;
    limitSize = limitSize.toLocaleLowerCase();
    const unitSize = {
      "b": 1,
      "kb": 1024,
      "mb": 1048576,
      "gb": 1073741824,
      "tb": 1099511627776,
      "pb": 1125899906842624
    }
    if (limitSize.indexOf("pb") >= 0) {
      limitSize = limitSize.replace("pb","");
      resSize = parseFloat(limitSize) * unitSize.pb;
    }
    else if (limitSize.indexOf("tb") >= 0) {
      limitSize = limitSize.replace("tb","");
      resSize = parseFloat(limitSize) * unitSize.tb;
    }
    else if (limitSize.indexOf("gb") >= 0) {
      limitSize = limitSize.replace("gb","");
      resSize = parseFloat(limitSize) * unitSize.gb;
    }
    else if (limitSize.indexOf("mb") >= 0) {
      limitSize = limitSize.replace("mb","");
      resSize = parseFloat(limitSize) * unitSize.mb;
    }
    else if (limitSize.indexOf("kb") >= 0) {
      limitSize = limitSize.replace("kb","");
      resSize = parseFloat(limitSize) * unitSize.kb;
    }
    else {
      resSize = -1;
    }
    return parseInt(resSize);
  },
  getDirName(dirName) {
    if (dirName != '' && dirName.indexOf('/') != dirName.length - 1) {
      dirName = dirName + '/'
    }
    return dirName;
  },
  getExtName(filename) {
    let dotIndex = filename.lastIndexOf('.');
    let extName ='';
    if (dotIndex != -1) {
      extName = filename.substring(dotIndex).toLowerCase();
    }
    return extName;
  },
  isEmptyObject(paraObj) {
    for (let key in paraObj){
      return false;
    }
    return true;
  }
}

export default  zcAliFile;

/* 调用格式:
  安装:在项目根目录下npm install ali-oss
  import OSS from 'ali-oss';

  //构造业务数据
  let ItemData = {};
  ItemData.SN = "xxx";
  ItemData.FileSN = "";
  ItemData.State = "Start";

  ItemData.Uploader = {};
  ItemData.Uploader.ProgTag = document.getElementById("spanProgress1");//进度条标签

  me.$ZcPublic.AliUp.doInit({
    AliOss: OSS,
    UserData: ItemData, //开发人员自定义返回对象
    FileCfg: {
      ButtonId: '上传按钮Id,可以是任意标签',
      Accept: 'mime_type如image/*,video/*,audio/*',
      ExtName: '允许的文件扩展名,如.jpg,.png,.gif,.mp4,.mp3等',
      MaxSize: '如20kb / 20mb / 20gb / 20tb / 20pb'
    },
    fnFileAdded: '表示文件已经添加到内存中,准备上传之前调用的方法',
    fnUpingProgress: '进度回调方法,参数有两个fn(percent百分比 , option返回自定义的UserData)',
    fnUpingSuccess: '成功回调方法,参数有两个fn(resJson返回后台数据 , option返回自定义的UserData)',
    fnUpingError: '失败回调方法',
    Scope:null
  });


  回调错误方法格式:
  myUpingError(e, options) {
    //主要判断e参数,e的结构为{ name: "错误标题", msg: "错误内容", errCode: "错误编号"}
    //错误编号列表:
    errCode = "errUnKnow"; // 表示未错误,直接将 msg显示出来即可
    errCode = "errUpPause"; // 表示上传暂停,无须提示
    errCode = "errSizeCfg"; // 表示限制文件大小的配置
    errCode = "errFileType"; // 表示限制文件类型
    errCode = "errFileSize"; // 表示限制文件大小
  }
 */

